#ifndef M14KC_H_
#define M14KC_H_

/*
 * Symbolic register names for 32 bit ABI
 */
#define zero    $0      /* wired zero */
#define AT      $1      /* assembler temp  - uppercase because of ".set at" */
#define v0      $2      /* return value */
#define v1      $3
#define a0      $4      /* argument registers */
#define a1      $5
#define a2      $6
#define a3      $7
#define t0      $8      /* caller saved */
#define t1      $9
#define t2      $10
#define t3      $11
#define t4      $12
#define t5      $13
#define t6      $14
#define t7      $15
#define s0      $16     /* callee saved */
#define s1      $17
#define s2      $18
#define s3      $19
#define s4      $20
#define s5      $21
#define s6      $22
#define s7      $23
#define t8      $24     /* caller saved */
#define t9      $25
#define jp      $25     /* PIC jump register */
#define k0      $26     /* kernel scratch */
#define k1      $27
#define gp      $28     /* global pointer */
#define sp      $29     /* stack pointer */
#define fp      $30     /* frame pointer */
#define s8      $30     /* same like fp! */
#define ra      $31     /* return address */

/*
 * Coprocessor 0 register names
 */
#define CP0_INDEX       $0
#define CP0_RANDOM      $1
#define CP0_ENTRYLO0    $2
#define CP0_ENTRYLO1    $3
#define CP0_CONTEXT     $4
#define CP0_PAGEMASK    $5
#define CP0_WIRED       $6
#define CP0_INFO        $7
#define CP0_BADVADDR    $8
#define CP0_COUNT       $9
#define CP0_ENTRYHI     $10
#define CP0_COMPARE     $11
#define CP0_STATUS      $12
#define CP0_INTCTL      $12,1
#define CP0_SRSCTL      $12,2
#define CP0_SRSMAP      $12,3
#define CP0_CAUSE       $13
#define CP0_EPC         $14
#define CP0_PRID        $15
#define CP0_EBASE       $15,1
#define CP0_CONFIG      $16
#define CP0_CONFIG1     $16,1
#define CP0_CONFIG2     $16,2
#define CP0_CONFIG3     $16,3
#define CP0_LLADDR      $17,0
#define CP0_WATCHLO     $18,0
#define CP0_WATCHHI     $19,0
#define CP0_XCONTEXT    $20
#define CP0_FRAMEMASK   $21
#define CP0_DIAGNOSTIC  $22
#define CP0_DEBUG       $23,0
#define CP0_DEPC        $24,0
#define CP0_PERFCTL     $25,0
#define CP0_PERFCNT     $25,1
#define CP0_ECC         $26
#define CP0_CACHEERR    $27
#define CP0_TAGLO       $28,0
#define CP0_DATALO      $28,1
#define CP0_TAGHI       $29,0
#define CP0_DATAHI      $29,1
#define CP0_ERROREPC    $30
#define CP0_DESAVE      $31,0

#define C0_CAUSE_TI		(1<<30)		// Timer Interrupt
#define C0_CAUSE_IP2	(1<<10)		// Hardware interrupt 0

#define C0_STS_UM		(1<<4)
#define C0_STS_ERL		(1<<2)
#define C0_STS_EXL		(1<<1)

#ifndef __ASSEMBLY__
/*
* MIPSR2 defines ehb for hazard avoidance
*	ehb means 'excution hazard barrier'
*/
static inline void __ehb(void)
{
	__asm__ __volatile__(
	"	.set	mips32r2	\n"
	"	ehb					\n"
	"	.set	mips0		\n");
}
#define mtc0_tlbw_hazard	__ehb
#define tlbw_use_hazard		__ehb
#define tlb_probe_hazard	__ehb

/*
 * porting from linux
 */
 
/*
 * Macros to access the system control coprocessor
 */

#define __read_32bit_c0_register(source, sel)				\
({ unsigned int __res;								\
	if (sel == 0)							\
		__asm__ __volatile__(					\
			"mfc0\t%0, " #source "\n\t"			\
			: "=r" (__res));				\
	else								\
		__asm__ __volatile__(					\
			".set\tmips32\n\t"				\
			"mfc0\t%0, " #source ", " #sel "\n\t"		\
			".set\tmips0\n\t"				\
			: "=r" (__res));				\
	__res;								\
})

#define __write_32bit_c0_register(register, sel, value)			\
do {									\
	if (sel == 0)							\
		__asm__ __volatile__(					\
			"mtc0\t%z0, " #register "\n\t"			\
			: : "Jr" ((unsigned int)(value)));		\
	else								\
		__asm__ __volatile__(					\
			".set\tmips32\n\t"				\
			"mtc0\t%z0, " #register ", " #sel "\n\t"	\
			".set\tmips0"					\
			: : "Jr" ((unsigned int)(value)));		\
} while (0)
#define __write_32bit_c0_register1(register, sel, value)			\
do {									\
		__asm__ __volatile__(					\
			"mtc0\t%0, " #register ", " #sel "\n\t"	\
			: : "r" (value));		\
} while (0)

#define read_c0_index()			__read_32bit_c0_register($0, 0)
#define write_c0_index(val)		__write_32bit_c0_register($0, 0, val)

#define read_c0_random()		__read_32bit_c0_register($1, 0)
#define write_c0_random(val)	__write_32bit_c0_register($1, 0, val)

#define read_c0_entrylo0()		__read_32bit_c0_register($2, 0)
#define write_c0_entrylo0(val)	__write_32bit_c0_register($2, 0, val)

#define read_c0_entrylo1()		__read_32bit_c0_register($3, 0)
#define write_c0_entrylo1(val)	__write_32bit_c0_register($3, 0, val)

#define read_c0_context()		__read_32bit_c0_register($4, 0)
#define write_c0_context(val)	__write_32bit_c0_register($4, 0, val)

#define read_c0_userlocal()		__read_32bit_c0_register($4, 2)
#define write_c0_userlocal(val)	__write_32bit_c0_register($4, 2, val)

#define read_c0_pagemask()		__read_32bit_c0_register($5, 0)
#define write_c0_pagemask(val)	__write_32bit_c0_register($5, 0, val)

#define read_c0_pagegrain()		__read_32bit_c0_register($5, 1)			// M14KC
#define write_c0_pagegrain(val)	__write_32bit_c0_register($5, 1, val)

#define read_c0_wired()			__read_32bit_c0_register($6, 0)
#define write_c0_wired(val)		__write_32bit_c0_register($6, 0, val)

#define read_c0_hwrena()		__read_32bit_c0_register($7, 0)			// M14KC
#define write_c0_hwrena(val)	__write_32bit_c0_register($7, 0, val)

#define read_c0_badvaddr()		__read_32bit_c0_register($8, 0)

#define read_c0_count()			__read_32bit_c0_register($9, 0)
#define write_c0_count(val)		__write_32bit_c0_register($9, 0, val)

#define read_c0_entryhi()		__read_32bit_c0_register($10, 0)
#define write_c0_entryhi(val)	__write_32bit_c0_register($10, 0, val)

#define read_c0_compare()		__read_32bit_c0_register($11, 0)
#define write_c0_compare(val)	__write_32bit_c0_register($11, 0, val)

#define read_c0_status()		__read_32bit_c0_register($12, 0)
// FIXME: for the macro CONFIG_MIPS_MT_SMTC
#ifdef CONFIG_MIPS_MT_SMTC
#define write_c0_status(val)						\
do {									\
	__write_32bit_c0_register($12, 0, val);				\
	__ehb();							\
} while (0)
#else
/*
 * Legacy non-SMTC code, which may be hazardous
 * but which might not support EHB
 */
#define write_c0_status(val)	__write_32bit_c0_register($12, 0, val)
#endif /* CONFIG_MIPS_MT_SMTC */

#define read_c0_intctl()		__read_32bit_c0_register($12, 1)		// M14KC
#define write_c0_intctl(val)	__write_32bit_c0_register($12, 1, val)

#define read_c0_srsctl()		__read_32bit_c0_register($12, 2)		// M14KC
#define write_c0_srsctl(val)	__write_32bit_c0_register($12, 2, val)

#define read_c0_srsmap()		__read_32bit_c0_register($12, 3)		// M14KC
#define write_c0_srsmap(val)	__write_32bit_c0_register($12, 3, val)

#define read_c0_viewipl()		__read_32bit_c0_register($12, 4)		// M14KC
#define write_c0_viewipl(val)	__write_32bit_c0_register($12, 4, val)

#define read_c0_srsmap2()		__read_32bit_c0_register($12, 5)		// M14KC
#define write_c0_srsmap2(val)	__write_32bit_c0_register($12, 5, val)

#define read_c0_cause()			__read_32bit_c0_register($13, 0)
#define write_c0_cause(val)		__write_32bit_c0_register($13, 0, val)

#define read_c0_viewripl()		__read_32bit_c0_register($13, 4)		// M14KC
#define write_c0_viewripl(val)	__write_32bit_c0_register($13, 4, val)

#define read_c0_epc()			__read_32bit_c0_register($14, 0)
#define write_c0_epc(val)		__write_32bit_c0_register($14, 0, val)

#define read_c0_prid()			__read_32bit_c0_register($15, 0)

#define read_c0_ebase()			__read_32bit_c0_register($15, 1)			// M14KC
#define write_c0_ebase(val)		__write_32bit_c0_register($15, 1, val)

#define read_c0_cdmmbase()		__read_32bit_c0_register($15, 2)			// M14KC
#define write_c0_cdmmbase(val)	__write_32bit_c0_register($15, 2, val)

#define read_c0_config()		__read_32bit_c0_register($16, 0)
#define read_c0_config1()		__read_32bit_c0_register($16, 1)
#define read_c0_config2()		__read_32bit_c0_register($16, 2)
#define read_c0_config3()		__read_32bit_c0_register($16, 3)
#define read_c0_config7()		__read_32bit_c0_register($16, 7)
#define write_c0_config(val)	__write_32bit_c0_register($16, 0, val)
#define write_c0_config1(val)	__write_32bit_c0_register($16, 1, val)
#define write_c0_config2(val)	__write_32bit_c0_register($16, 2, val)
#define write_c0_config3(val)	__write_32bit_c0_register($16, 3, val)
#define write_c0_config7(val)	__write_32bit_c0_register($16, 7, val)

#define read_c0_lladdr()		__read_32bit_c0_register($17, 0)			// M14KC
#define write_c0_lladdr(val)	__write_32bit_c0_register($17, 0, val)

/*
 * The WatchLo register.  There may be upto 8 of them.
 */
#define read_c0_watchlo0()	__read_32bit_c0_register($18, 0)
#define read_c0_watchlo1()	__read_32bit_c0_register($18, 1)
#define read_c0_watchlo2()	__read_32bit_c0_register($18, 2)
#define read_c0_watchlo3()	__read_32bit_c0_register($18, 3)
#define read_c0_watchlo4()	__read_32bit_c0_register($18, 4)
#define read_c0_watchlo5()	__read_32bit_c0_register($18, 5)
#define read_c0_watchlo6()	__read_32bit_c0_register($18, 6)
#define read_c0_watchlo7()	__read_32bit_c0_register($18, 7)

#define write_c0_watchlo0(val)	__write_32bit_c0_register($18, 0, val)
#define write_c0_watchlo1(val)	__write_32bit_c0_register($18, 1, val)
#define write_c0_watchlo2(val)	__write_32bit_c0_register($18, 2, val)
#define write_c0_watchlo3(val)	__write_32bit_c0_register($18, 3, val)
#define write_c0_watchlo4(val)	__write_32bit_c0_register($18, 4, val)
#define write_c0_watchlo5(val)	__write_32bit_c0_register($18, 5, val)
#define write_c0_watchlo6(val)	__write_32bit_c0_register($18, 6, val)
#define write_c0_watchlo7(val)	__write_32bit_c0_register($18, 7, val)

/*
 * The WatchHi register.  There may be upto 8 of them.
 */
#define read_c0_watchhi0()		__read_32bit_c0_register($19, 0)
#define read_c0_watchhi1()		__read_32bit_c0_register($19, 1)
#define read_c0_watchhi2()		__read_32bit_c0_register($19, 2)
#define read_c0_watchhi3()		__read_32bit_c0_register($19, 3)
#define read_c0_watchhi4()		__read_32bit_c0_register($19, 4)
#define read_c0_watchhi5()		__read_32bit_c0_register($19, 5)
#define read_c0_watchhi6()		__read_32bit_c0_register($19, 6)
#define read_c0_watchhi7()		__read_32bit_c0_register($19, 7)

#define write_c0_watchhi0(val)	__write_32bit_c0_register($19, 0, val)
#define write_c0_watchhi1(val)	__write_32bit_c0_register($19, 1, val)
#define write_c0_watchhi2(val)	__write_32bit_c0_register($19, 2, val)
#define write_c0_watchhi3(val)	__write_32bit_c0_register($19, 3, val)
#define write_c0_watchhi4(val)	__write_32bit_c0_register($19, 4, val)
#define write_c0_watchhi5(val)	__write_32bit_c0_register($19, 5, val)
#define write_c0_watchhi6(val)	__write_32bit_c0_register($19, 6, val)
#define write_c0_watchhi7(val)	__write_32bit_c0_register($19, 7, val)

#define read_c0_debug()			__read_32bit_c0_register($23, 0)
#define write_c0_debug(val)		__write_32bit_c0_register($23, 0, val)

#define read_c0_tracectrl1()	__read_32bit_c0_register($23, 1)		// M14KC
#define write_c0_tracectrl1(val)	__write_32bit_c0_register($23, 1, val)

#define read_c0_tracectrl2()	__read_32bit_c0_register($23, 2)		// M14KC
#define write_c0_tracectrl2(val)	__write_32bit_c0_register($23, 2, val)

#define read_c0_usertrcdt1()	__read_32bit_c0_register($23, 3)		// M14KC
#define write_c0_usertrcdt1(val)	__write_32bit_c0_register($23, 3, val)

#define read_c0_usertrcdt2()	__read_32bit_c0_register($24, 3)		// M14KC
#define write_c0_usertrcdt2(val)	__write_32bit_c0_register($24, 3, val)

#define read_c0_tracebpc()		__read_32bit_c0_register($23, 4)		// M14KC
#define write_c0_tracecbpc(val)	__write_32bit_c0_register($23, 4, val)

#define read_c0_debug2()		__read_32bit_c0_register($23, 6)
#define write_c0_debug2(val)	__write_32bit_c0_register($23, 6, val)

#define read_c0_depc()			__read_32bit_c0_register($24, 0)
#define write_c0_depc(val)		__write_32bit_c0_register($24, 0, val)

/*
 * MIPS32 performance control & counters
 */
#define read_c0_perfctrl0()		__read_32bit_c0_register($25, 0)
#define write_c0_perfctrl0(val)	__write_32bit_c0_register($25, 0, val)
#define read_c0_perfcntr0()		__read_32bit_c0_register($25, 1)
#define write_c0_perfcntr0(val)	__write_32bit_c0_register($25, 1, val)
#define read_c0_perfctrl1()		__read_32bit_c0_register($25, 2)
#define write_c0_perfctrl1(val)	__write_32bit_c0_register($25, 2, val)
#define read_c0_perfcntr1()		__read_32bit_c0_register($25, 3)
#define write_c0_perfcntr1(val)	__write_32bit_c0_register($25, 3, val)

#define read_c0_errctl()		__read_32bit_c0_register($26, 0)		// M14KC
#define write_c0_errctl(val)	__write_32bit_c0_register($26, 0, val)

#define read_c0_cacheerr()		__read_32bit_c0_register($27, 0)

#define read_c0_taglo()			__read_32bit_c0_register($28, 0)
#define write_c0_taglo(val)		__write_32bit_c0_register($28, 0, val)

#define read_c0_dtaglo()		__read_32bit_c0_register($28, 1)
#define write_c0_dtaglo(val)	__write_32bit_c0_register($28, 1, val)

#define read_c0_errorepc()		__read_32bit_c0_register($30, 0)
#define write_c0_errorepc(val)	__write_32bit_c0_register($30, 0, val)

#define read_c0_desave()		__read_32bit_c0_register($30, 0)		// M14KC
#define write_c0_desave(val)	__write_32bit_c0_register($30, 0, val)

/*
 * TLB operations.
 *
 * It is responsibility of the caller to take care of any TLB hazards.
 */
static inline void tlb_probe(void)
{
	__asm__ __volatile__(
		".set noreorder\n\t"
		"tlbp\n\t"
		".set reorder");
}

static inline void tlb_read(void)
{
	__asm__ __volatile__(
		".set noreorder\n\t"
		"tlbr\n\t"
		".set reorder");
}

static inline void tlb_write_indexed(void)
{
	__asm__ __volatile__(
		".set noreorder\n\t"
		"tlbwi\n\t"
		".set reorder");
}

static inline void tlb_write_random(void)
{
	__asm__ __volatile__(
		".set noreorder\n\t"
		"tlbwr\n\t"
		".set reorder");
}

/*
 * Manipulate bits in a c0 register.
 */
/*
 * SMTC Linux requires shutting-down microthread scheduling
 * during CP0 register read-modify-write sequences.
 */
#define __BUILD_SET_C0(name)					\
static inline unsigned int					\
set_c0_##name(unsigned int set)					\
{								\
	unsigned int res, new;					\
								\
	res = read_c0_##name();					\
	new = res | set;					\
	write_c0_##name(new);					\
								\
	return res;						\
}								\
								\
static inline unsigned int					\
clear_c0_##name(unsigned int clear)				\
{								\
	unsigned int res, new;					\
								\
	res = read_c0_##name();					\
	new = res & ~clear;					\
	write_c0_##name(new);					\
								\
	return res;						\
}								\
								\
static inline unsigned int					\
change_c0_##name(unsigned int change, unsigned int val)		\
{								\
	unsigned int res, new;					\
								\
	res = read_c0_##name();					\
	new = res & ~change;					\
	new |= (val & change);					\
	write_c0_##name(new);					\
								\
	return res;						\
}

__BUILD_SET_C0(status)
__BUILD_SET_C0(cause)
__BUILD_SET_C0(config)
__BUILD_SET_C0(intctl)
__BUILD_SET_C0(srsmap)

#endif	// __ASSEMBLY__

#endif /* M14KC_H_ */
